# Each team member would need to set their directory path to variable "project_dir"
# we will make sure everything else is relative to "project_dir"
project_dir <- "/home/admin-12/Documents/IMARTICUS/Data-Riders/EDA"
setwd(project_dir)
# Setup Packages
load_packages <- function () {
# Imports
packages <- c("VIM", "dplyr", "plotly", "psych", "corrplot", "cluster", "factoextra", "psych", "tm", "wordcloud2")
installed_packages <- packages %in% rownames(installed.packages())
if (any(installed_packages == FALSE)) {
install.packages(packages[!installed_packages])
}
# Packages loading with suppressed messages
suppressMessages(invisible(lapply(packages, library, character.only = TRUE)))
}
load_packages()
# Get the Raw Data from the file
read_file <- function () {
data <- read.csv("data/cereals_data.csv")
return (data)
}
# Handle missing values
handle_missing_values <- function (input) {
output <- input
output <- kNN(output)
return (output)
}
# Clearn the data to make it good for processing
# eg. delete unwanted rows, change data types etc
data_processing <- function (input) {
output <- input
output <- handle_missing_values(output)
# Set company names
output$mfr_names <- as.character(output$mfr)
output$mfr_names[output$mfr_names=="A"] <- "American Home Food Products"
output$mfr_names[output$mfr_names=="G"] <- "General Mills"
output$mfr_names[output$mfr_names=="K"] <- "Kelloggs"
output$mfr_names[output$mfr_names=="N"] <- "Nabisco"
output$mfr_names[output$mfr_names=="P"] <- "Post"
output$mfr_names[output$mfr_names=="Q"] <- "Quaker Oats"
output$mfr_names[output$mfr_names=="R"] <- "Ralston Purina"
output$mfr_names_factor = as.factor(output$mfr_names)
# Calorie Categories
output <- within(output, {
calories_category <- NA
calories_category[calories>=50&calories<80] <- "L"
calories_category[calories>=80&calories<110] <- "M"
calories_category[calories>=110] <- "H"
})
# some data processing steps that would be required
return (output)
}
# Get the Data Frame for the data
get_data <- function () {
raw <- read_file()
data <- data_processing(raw)
return (data)
}
data <- get_data()
data_grp_mfr <- data %>% group_by(mfr_names_factor)
Part 1: Understanding Variables
Overall View
draw_density_plot <- function (value_set, xlab) {
skewness <- round(skew(value_set), 2)
mean <- round(mean(value_set), 2)
median <- round(median(value_set), 2)
title <- paste(xlab, "Density Chart | ", "Skewness:", skewness)
plot(density(value_set), ylab = "Probabilty Density", xlab = xlab, main=title,)
abline(v=mean, col="red")
abline(v=median, col="blue")
}
Distribution of Calories (in the Products)
draw_density_plot(data$calories, "Calories")

Distribution of Ratings (for the Products)
draw_density_plot(data$rating, "Rating")

Part 2: Data Insights
Distribution of Rating vs Calorie Category
data %>% ggplot(aes(x = rating, fill = calories_category)) + geom_histogram() + scale_fill_brewer(palette = "Set1") +
scale_x_continuous(name = "Ratings", expand = c(0,0)) +
labs(fill = " Cal ", y ='Count', title = "Distribution of Rating vs Calorie Category", subtitle = "Higher the calories, Lower is the Rating") +
theme_classic()
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

Relationship of one variable with another
cor_result <- cor((data_grp_mfr %>% select_if(is.numeric))[-1])
corrplot(cor_result)

heatmap(cor_result)

good_bad_corr <- function (cor_result_filter) {
#cor_result_filter <-
cor_result_filter_names <- names(cor_result_filter)
names(cor_result_filter) <- NULL
cor_result_df <- data.frame(cor_result_filter_names, cor_result_filter) %>% arrange(cor_result_filter)
names(cor_result_df) <- c("Parameters", "Corellation")
ggplot(cor_result_df, aes(x=Parameters, y=Corellation)) + geom_bar(stat = "identity") +
theme(axis.text.x=element_text(colour="black"), axis.text.y=element_text(colour="black"))
}
Influencers for Ratings
good_bad_corr(cor_result["rating",])

Influencers for Calories
good_bad_corr(cor_result["calories",])

Whats you get in one Serving
data %>% ggplot(aes(x = cups, fill = mfr_names)) +
geom_histogram() +
scale_x_continuous(name = "# of Cups", expand = c(0,0)) +
labs(fill = "Manufacturer", title = "Distribution of Cups per Serving",
subtitle = "different cups for servings", y="# of Products") +
theme_classic() + scale_fill_brewer(palette="Dark2")
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

data %>% ggplot(aes(x = weight, fill = mfr_names)) + geom_histogram() +
scale_x_continuous(name = "Weight (in ounces)", expand = c(0,0)) +
labs(fill = "Manufacturer", title = "Distribution of Weight per Serving", subtitle = "Weight per serving") +
theme_classic() + scale_fill_brewer(palette="Dark2")
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

Best in the Market
d <- data %>% arrange(rating) %>% head(4) %>% select(name, rating)
ggplot(data=d, aes(x=name, y=rating)) + geom_bar(stat = "identity") +
labs(y="Ratings") + scale_fill_brewer(palette="Dark2") +
theme(axis.text.x=element_text(colour="black"), axis.text.y=element_text(colour="black"))

Part 3: Analysis by company
data_grp_mfr %>% plot_ly(y= ~rating, x= ~mfr_names_factor, type = "box", color= ~mfr_names_factor) %>%
layout(title="Company wise Rating Consistency", xaxis=list(title="Manufactures"), yaxis=list(title="Rating"))
Part 4: Overall Picture
Word Cloud (error in markdown)
get_file_content <- function () {
txt <- readLines("/home/admin-12/Documents/IMARTICUS/Data-Riders/EDA/data/health.txt")
txt <- paste(txt, collapse = " ")
txt <- tolower(txt)
txt <- gsub("[^a-zA-Z]", " ", txt)
txt <- gsub("\\s+", " ", txt)
txt <- removeWords(txt, stopwords())
words <- strsplit(txt, " ")
word_freq <- table(words)
return (word_freq)
}
word_freq <- get_file_content()
wordcloud2(word_freq, shape="star", size=10)
Feature Based Grouping (Clusters)
cluster_data <- data %>% select(calories, rating, protein, fat) %>% scale
row.names(cluster_data) <- data[,1]
km.res <- kmeans(cluster_data, 5, nstart = 25)
fviz_cluster(km.res, data=cluster_data, palette = "jco", ggtheme = theme_minimal())

LS0tCnRpdGxlOiAiRGF0YSBSaWRlcnM6IEVEQSBNaW5pLVByb2plY3QiCm91dHB1dDoKICBodG1sX25vdGVib29rOgogICAgY29kZV9mb2xkaW5nOiBoaWRlCi0tLQoKPHN0eWxlIHR5cGU9InRleHQvY3NzIj4KCmg1IHsKICAgIGJhY2tncm91bmQ6IHJnYmEoMTA4LCAxMDgsIDEwOCwgMC4zNSk7CiAgICBib3JkZXItdG9wOiAxcHggc29saWQgIzg0ODQ4NDsKICAgIGJvcmRlci1ib3R0b206IDFweCBzb2xpZCAjODQ4NDg0OwogICAgbWFyZ2luLXRvcDogMHB4OwogICAgcGFkZGluZzogMTBweCAxMHB4OwogICAgZm9udC13ZWlnaHQ6IGJvbGQ7Cn0KaDU6aG92ZXIgewogIGJhY2tncm91bmQ6ICNmZmViM2I7Cn0KCmgyIHsKICBiYWNrZ3JvdW5kOiAjMjEyMTIxOwogIGNvbG9yOiB3aGl0ZTsKICBwYWRkaW5nOiA4cHggOHB4OwogIG1hcmdpbi10b3A6IDBweDsKICBtYXJnaW4tYm90dG9tOiAwcHg7Cn0KCi5jb250YWluZXItcGFydCB7CiAgYm9yZGVyOiAxcHggc29saWQgI2EyYTJhMjsKICBtYXJnaW4tYm90dG9tOiAzNXB4Owp9CgoubWFpbi1jb250YWluZXIgewogIG1heC13aWR0aDogMTMwMHB4OwogIG1hcmdpbi1sZWZ0OiBhdXRvOwogIG1hcmdpbi1yaWdodDogYXV0bzsKfQo8L3N0eWxlPgoKYGBge3J9CiMgRWFjaCB0ZWFtIG1lbWJlciB3b3VsZCBuZWVkIHRvIHNldCB0aGVpciBkaXJlY3RvcnkgcGF0aCB0byB2YXJpYWJsZSAicHJvamVjdF9kaXIiCiMgd2Ugd2lsbCBtYWtlIHN1cmUgZXZlcnl0aGluZyBlbHNlIGlzIHJlbGF0aXZlIHRvICJwcm9qZWN0X2RpciIKcHJvamVjdF9kaXIgPC0gIi9ob21lL2FkbWluLTEyL0RvY3VtZW50cy9JTUFSVElDVVMvRGF0YS1SaWRlcnMvRURBIgpzZXR3ZChwcm9qZWN0X2RpcikKCiMgU2V0dXAgUGFja2FnZXMKbG9hZF9wYWNrYWdlcyA8LSBmdW5jdGlvbiAoKSB7CiAgIyBJbXBvcnRzCiAgcGFja2FnZXMgPC0gYygiVklNIiwgImRwbHlyIiwgInBsb3RseSIsICJwc3ljaCIsICJjb3JycGxvdCIsICJjbHVzdGVyIiwgImZhY3RvZXh0cmEiLCAicHN5Y2giLCAidG0iLCAid29yZGNsb3VkMiIpCiAgaW5zdGFsbGVkX3BhY2thZ2VzIDwtIHBhY2thZ2VzICVpbiUgcm93bmFtZXMoaW5zdGFsbGVkLnBhY2thZ2VzKCkpCiAgaWYgKGFueShpbnN0YWxsZWRfcGFja2FnZXMgPT0gRkFMU0UpKSB7CiAgICBpbnN0YWxsLnBhY2thZ2VzKHBhY2thZ2VzWyFpbnN0YWxsZWRfcGFja2FnZXNdKQogIH0KICAjIFBhY2thZ2VzIGxvYWRpbmcgd2l0aCBzdXBwcmVzc2VkIG1lc3NhZ2VzCiAgc3VwcHJlc3NNZXNzYWdlcyhpbnZpc2libGUobGFwcGx5KHBhY2thZ2VzLCBsaWJyYXJ5LCBjaGFyYWN0ZXIub25seSA9IFRSVUUpKSkKfQpsb2FkX3BhY2thZ2VzKCkKCiMgR2V0IHRoZSBSYXcgRGF0YSBmcm9tIHRoZSBmaWxlCnJlYWRfZmlsZSA8LSBmdW5jdGlvbiAoKSB7CiAgZGF0YSA8LSByZWFkLmNzdigiZGF0YS9jZXJlYWxzX2RhdGEuY3N2IikKICByZXR1cm4gKGRhdGEpCn0KCiMgSGFuZGxlIG1pc3NpbmcgdmFsdWVzCmhhbmRsZV9taXNzaW5nX3ZhbHVlcyA8LSBmdW5jdGlvbiAoaW5wdXQpIHsKICBvdXRwdXQgPC0gaW5wdXQKICBvdXRwdXQgPC0ga05OKG91dHB1dCkKICByZXR1cm4gKG91dHB1dCkKfQoKIyBDbGVhcm4gdGhlIGRhdGEgdG8gbWFrZSBpdCBnb29kIGZvciBwcm9jZXNzaW5nCiMgZWcuIGRlbGV0ZSB1bndhbnRlZCByb3dzLCBjaGFuZ2UgZGF0YSB0eXBlcyBldGMKZGF0YV9wcm9jZXNzaW5nIDwtIGZ1bmN0aW9uIChpbnB1dCkgewogIG91dHB1dCA8LSBpbnB1dAogIG91dHB1dCA8LSBoYW5kbGVfbWlzc2luZ192YWx1ZXMob3V0cHV0KQoKICAjIFNldCBjb21wYW55IG5hbWVzCiAgb3V0cHV0JG1mcl9uYW1lcyA8LSBhcy5jaGFyYWN0ZXIob3V0cHV0JG1mcikKICBvdXRwdXQkbWZyX25hbWVzW291dHB1dCRtZnJfbmFtZXM9PSJBIl0gPC0gIkFtZXJpY2FuIEhvbWUgRm9vZCBQcm9kdWN0cyIKICBvdXRwdXQkbWZyX25hbWVzW291dHB1dCRtZnJfbmFtZXM9PSJHIl0gPC0gIkdlbmVyYWwgTWlsbHMiCiAgb3V0cHV0JG1mcl9uYW1lc1tvdXRwdXQkbWZyX25hbWVzPT0iSyJdIDwtICJLZWxsb2dncyIKICBvdXRwdXQkbWZyX25hbWVzW291dHB1dCRtZnJfbmFtZXM9PSJOIl0gPC0gIk5hYmlzY28iCiAgb3V0cHV0JG1mcl9uYW1lc1tvdXRwdXQkbWZyX25hbWVzPT0iUCJdIDwtICJQb3N0IgogIG91dHB1dCRtZnJfbmFtZXNbb3V0cHV0JG1mcl9uYW1lcz09IlEiXSA8LSAiUXVha2VyIE9hdHMiCiAgb3V0cHV0JG1mcl9uYW1lc1tvdXRwdXQkbWZyX25hbWVzPT0iUiJdIDwtICJSYWxzdG9uIFB1cmluYSIKICBvdXRwdXQkbWZyX25hbWVzX2ZhY3RvciA9IGFzLmZhY3RvcihvdXRwdXQkbWZyX25hbWVzKQoKICAjIENhbG9yaWUgQ2F0ZWdvcmllcwogIG91dHB1dCA8LSB3aXRoaW4ob3V0cHV0LCB7CiAgICBjYWxvcmllc19jYXRlZ29yeSA8LSBOQQogICAgY2Fsb3JpZXNfY2F0ZWdvcnlbY2Fsb3JpZXM+PTUwJmNhbG9yaWVzPDgwXSA8LSAiTCIKICAgIGNhbG9yaWVzX2NhdGVnb3J5W2NhbG9yaWVzPj04MCZjYWxvcmllczwxMTBdIDwtICJNIgogICAgY2Fsb3JpZXNfY2F0ZWdvcnlbY2Fsb3JpZXM+PTExMF0gPC0gIkgiCiAgfSkKCiAgIyBzb21lIGRhdGEgcHJvY2Vzc2luZyBzdGVwcyB0aGF0IHdvdWxkIGJlIHJlcXVpcmVkCiAgcmV0dXJuIChvdXRwdXQpCn0KCiMgR2V0IHRoZSBEYXRhIEZyYW1lIGZvciB0aGUgZGF0YQpnZXRfZGF0YSA8LSBmdW5jdGlvbiAoKSB7CiAgcmF3IDwtIHJlYWRfZmlsZSgpCiAgZGF0YSA8LSBkYXRhX3Byb2Nlc3NpbmcocmF3KQogIHJldHVybiAoZGF0YSkKfQoKZGF0YSA8LSBnZXRfZGF0YSgpCmRhdGFfZ3JwX21mciA8LSBkYXRhICU+JSBncm91cF9ieShtZnJfbmFtZXNfZmFjdG9yKQpgYGAKCjwhLS0gLS0tLS0tLS0tLSAtLS0tLS0tLS0tIC0tLS0tLS0tLS0gLS0tLS0tLS0tLSAtLT4KPGRpdiBjbGFzcz0iY29udGFpbmVyLXBhcnQiPgo8aDI+UGFydCAxOiBVbmRlcnN0YW5kaW5nIFZhcmlhYmxlczwvaDE+Cgo8aDU+T3ZlcmFsbCBWaWV3PC9oNT4KCmBgYHtyIGVjaG89RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmRlc2NyaWJlKGRhdGEgJT4lIHNlbGVjdF9pZihpcy5udW1lcmljKSkKYGBgCgpgYGB7cn0KZHJhd19kZW5zaXR5X3Bsb3QgPC0gZnVuY3Rpb24gKHZhbHVlX3NldCwgeGxhYikgewogIHNrZXduZXNzIDwtIHJvdW5kKHNrZXcodmFsdWVfc2V0KSwgMikKICBtZWFuIDwtIHJvdW5kKG1lYW4odmFsdWVfc2V0KSwgMikKICBtZWRpYW4gPC0gcm91bmQobWVkaWFuKHZhbHVlX3NldCksIDIpCiAgdGl0bGUgPC0gcGFzdGUoeGxhYiwgIkRlbnNpdHkgQ2hhcnQgICB8ICAiLCAiU2tld25lc3M6Iiwgc2tld25lc3MpCiAgcGxvdChkZW5zaXR5KHZhbHVlX3NldCksIHlsYWIgPSAiUHJvYmFiaWx0eSBEZW5zaXR5IiwgeGxhYiA9IHhsYWIsIG1haW49dGl0bGUsKQogIGFibGluZSh2PW1lYW4sIGNvbD0icmVkIikKICBhYmxpbmUodj1tZWRpYW4sIGNvbD0iYmx1ZSIpCn0KYGBgCgo8aDU+RGlzdHJpYnV0aW9uIG9mIENhbG9yaWVzIChpbiB0aGUgUHJvZHVjdHMpPC9oNT4KYGBge3J9CmRyYXdfZGVuc2l0eV9wbG90KGRhdGEkY2Fsb3JpZXMsICJDYWxvcmllcyIpCmBgYAoKPGg1PkRpc3RyaWJ1dGlvbiBvZiBSYXRpbmdzIChmb3IgdGhlIFByb2R1Y3RzKTwvaDU+CmBgYHtyfQpkcmF3X2RlbnNpdHlfcGxvdChkYXRhJHJhdGluZywgIlJhdGluZyIpCmBgYAoKPC9kaXY+Cgo8IS0tIC0tLS0tLS0tLS0gLS0tLS0tLS0tLSAtLS0tLS0tLS0tIC0tLS0tLS0tLS0gLS0+CjxkaXYgY2xhc3M9ImNvbnRhaW5lci1wYXJ0Ij4KPGgyPlBhcnQgMjogRGF0YSBJbnNpZ2h0czwvaDE+Cgo8aDU+RGlzdHJpYnV0aW9uIG9mIFJhdGluZyB2cyBDYWxvcmllIENhdGVnb3J5PC9oNT4KYGBge3J9CmRhdGEgJT4lIGdncGxvdChhZXMoeCA9IHJhdGluZywgZmlsbCA9IGNhbG9yaWVzX2NhdGVnb3J5KSkgKyBnZW9tX2hpc3RvZ3JhbSgpICsgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJTZXQxIikgKwogICAgICAgIHNjYWxlX3hfY29udGludW91cyhuYW1lID0gIlJhdGluZ3MiLCBleHBhbmQgPSBjKDAsMCkpICsKICAgICAgICBsYWJzKGZpbGwgPSAiIENhbCAiLCB5ID0nQ291bnQnLCB0aXRsZSA9ICJEaXN0cmlidXRpb24gb2YgUmF0aW5nIHZzIENhbG9yaWUgQ2F0ZWdvcnkiLCBzdWJ0aXRsZSA9ICJIaWdoZXIgdGhlIGNhbG9yaWVzLCBMb3dlciBpcyB0aGUgUmF0aW5nIikgKwogICAgICAgIHRoZW1lX2NsYXNzaWMoKQpgYGAKCjxoNT5SZWxhdGlvbnNoaXAgb2Ygb25lIHZhcmlhYmxlIHdpdGggYW5vdGhlcjwvaDU+CmBgYHtyfQpjb3JfcmVzdWx0IDwtIGNvcigoZGF0YV9ncnBfbWZyICU+JSBzZWxlY3RfaWYoaXMubnVtZXJpYykpWy0xXSkKY29ycnBsb3QoY29yX3Jlc3VsdCkKaGVhdG1hcChjb3JfcmVzdWx0KQpgYGAKCmBgYHtyfQpnb29kX2JhZF9jb3JyIDwtIGZ1bmN0aW9uIChjb3JfcmVzdWx0X2ZpbHRlcikgewogICNjb3JfcmVzdWx0X2ZpbHRlciA8LQogIGNvcl9yZXN1bHRfZmlsdGVyX25hbWVzIDwtIG5hbWVzKGNvcl9yZXN1bHRfZmlsdGVyKQogIG5hbWVzKGNvcl9yZXN1bHRfZmlsdGVyKSA8LSBOVUxMCiAgY29yX3Jlc3VsdF9kZiA8LSBkYXRhLmZyYW1lKGNvcl9yZXN1bHRfZmlsdGVyX25hbWVzLCBjb3JfcmVzdWx0X2ZpbHRlcikgJT4lIGFycmFuZ2UoY29yX3Jlc3VsdF9maWx0ZXIpCiAgbmFtZXMoY29yX3Jlc3VsdF9kZikgPC0gYygiUGFyYW1ldGVycyIsICJDb3JlbGxhdGlvbiIpCiAgZ2dwbG90KGNvcl9yZXN1bHRfZGYsIGFlcyh4PVBhcmFtZXRlcnMsIHk9Q29yZWxsYXRpb24pKSArIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiKSArCiAgICAgICAgICB0aGVtZShheGlzLnRleHQueD1lbGVtZW50X3RleHQoY29sb3VyPSJibGFjayIpLCBheGlzLnRleHQueT1lbGVtZW50X3RleHQoY29sb3VyPSJibGFjayIpKQp9CmBgYAoKPGg1PkluZmx1ZW5jZXJzIGZvciBSYXRpbmdzPC9oNT4KYGBge3J9Cmdvb2RfYmFkX2NvcnIoY29yX3Jlc3VsdFsicmF0aW5nIixdKQpgYGAKCjxoNT5JbmZsdWVuY2VycyBmb3IgQ2Fsb3JpZXM8L2g1PgpgYGB7cn0KZ29vZF9iYWRfY29ycihjb3JfcmVzdWx0WyJjYWxvcmllcyIsXSkKYGBgCgo8aDU+V2hhdHMgeW91IGdldCBpbiBvbmUgU2VydmluZzwvaDU+CmBgYHtyfQpkYXRhICU+JSBnZ3Bsb3QoYWVzKHggPSBjdXBzLCBmaWxsID0gbWZyX25hbWVzKSkgKwogICAgICAgIGdlb21faGlzdG9ncmFtKCkgKwogICAgICAgIHNjYWxlX3hfY29udGludW91cyhuYW1lID0gIiMgb2YgQ3VwcyIsIGV4cGFuZCA9IGMoMCwwKSkgKwogICAgICAgIGxhYnMoZmlsbCA9ICJNYW51ZmFjdHVyZXIiLCB0aXRsZSA9ICJEaXN0cmlidXRpb24gb2YgQ3VwcyBwZXIgU2VydmluZyIsCiAgICAgICAgICAgICBzdWJ0aXRsZSA9ICJkaWZmZXJlbnQgY3VwcyBmb3Igc2VydmluZ3MiLCB5PSIjIG9mIFByb2R1Y3RzIikgKwogICAgICAgIHRoZW1lX2NsYXNzaWMoKSArIHNjYWxlX2ZpbGxfYnJld2VyKHBhbGV0dGU9IkRhcmsyIikKYGBgCgpgYGB7cn0KZGF0YSAlPiUgZ2dwbG90KGFlcyh4ID0gd2VpZ2h0LCBmaWxsID0gbWZyX25hbWVzKSkgKyBnZW9tX2hpc3RvZ3JhbSgpICsKICAgIHNjYWxlX3hfY29udGludW91cyhuYW1lID0gIldlaWdodCAoaW4gb3VuY2VzKSIsIGV4cGFuZCA9IGMoMCwwKSkgKwogICAgbGFicyhmaWxsID0gIk1hbnVmYWN0dXJlciIsIHRpdGxlID0gIkRpc3RyaWJ1dGlvbiBvZiBXZWlnaHQgcGVyIFNlcnZpbmciLCBzdWJ0aXRsZSA9ICJXZWlnaHQgcGVyIHNlcnZpbmciKSArCiAgICB0aGVtZV9jbGFzc2ljKCkgKyBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlPSJEYXJrMiIpCmBgYAoKPGg1PkJlc3QgaW4gdGhlIE1hcmtldDwvaDU+CmBgYHtyfQpkIDwtIGRhdGEgJT4lIGFycmFuZ2UocmF0aW5nKSAlPiUgaGVhZCg0KSAlPiUgc2VsZWN0KG5hbWUsIHJhdGluZykKZ2dwbG90KGRhdGE9ZCwgYWVzKHg9bmFtZSwgeT1yYXRpbmcpKSArIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiKSArCiAgICAgICAgbGFicyh5PSJSYXRpbmdzIikgKyBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlPSJEYXJrMiIpICsKICAgICAgICB0aGVtZShheGlzLnRleHQueD1lbGVtZW50X3RleHQoY29sb3VyPSJibGFjayIpLCBheGlzLnRleHQueT1lbGVtZW50X3RleHQoY29sb3VyPSJibGFjayIpKQpgYGAKCjwvZGl2PgoKPCEtLSAtLS0tLS0tLS0tIC0tLS0tLS0tLS0gLS0tLS0tLS0tLSAtLS0tLS0tLS0tIC0tPgo8ZGl2IGNsYXNzPSJjb250YWluZXItcGFydCI+CjxoMj5QYXJ0IDM6IEFuYWx5c2lzIGJ5IGNvbXBhbnk8L2gxPgoKYGBge3Igb3V0LndpZHRoPSIxMDAlIn0KZGF0YV9ncnBfbWZyICU+JSBwbG90X2x5KHk9IH5yYXRpbmcsIHg9IH5tZnJfbmFtZXNfZmFjdG9yLCB0eXBlID0gImJveCIsIGNvbG9yPSB+bWZyX25hbWVzX2ZhY3RvcikgJT4lCiAgbGF5b3V0KHRpdGxlPSJDb21wYW55IHdpc2UgUmF0aW5nIENvbnNpc3RlbmN5IiwgeGF4aXM9bGlzdCh0aXRsZT0iTWFudWZhY3R1cmVzIiksIHlheGlzPWxpc3QodGl0bGU9IlJhdGluZyIpKQpgYGAKPC9kaXY+Cgo8ZGl2IGNsYXNzPSJjb250YWluZXItcGFydCI+CjxoMj5QYXJ0IDQ6IE92ZXJhbGwgUGljdHVyZTwvaDE+CgpXb3JkIENsb3VkIChlcnJvciBpbiBtYXJrZG93bikKYGBge3J9CmdldF9maWxlX2NvbnRlbnQgPC0gZnVuY3Rpb24gKCkgewogIHR4dCA8LSByZWFkTGluZXMoIi9ob21lL2FkbWluLTEyL0RvY3VtZW50cy9JTUFSVElDVVMvRGF0YS1SaWRlcnMvRURBL2RhdGEvaGVhbHRoLnR4dCIpCiAgdHh0IDwtIHBhc3RlKHR4dCwgY29sbGFwc2UgPSAiICIpCiAgdHh0IDwtIHRvbG93ZXIodHh0KQogIHR4dCA8LSBnc3ViKCJbXmEtekEtWl0iLCAiICIsIHR4dCkKICB0eHQgPC0gZ3N1YigiXFxzKyIsICIgIiwgdHh0KQogIHR4dCA8LSByZW1vdmVXb3Jkcyh0eHQsIHN0b3B3b3JkcygpKQogIHdvcmRzIDwtIHN0cnNwbGl0KHR4dCwgIiAiKQogIHdvcmRfZnJlcSA8LSB0YWJsZSh3b3JkcykKICByZXR1cm4gKHdvcmRfZnJlcSkKfQp3b3JkX2ZyZXEgPC0gZ2V0X2ZpbGVfY29udGVudCgpCndvcmRjbG91ZDIod29yZF9mcmVxLCBzaGFwZT0ic3RhciIsIHNpemU9MTApCmBgYAoKPGg1PkZlYXR1cmUgQmFzZWQgR3JvdXBpbmcgKENsdXN0ZXJzKTwvaDU+CmBgYHtyfQpjbHVzdGVyX2RhdGEgPC0gZGF0YSAlPiUgc2VsZWN0KGNhbG9yaWVzLCByYXRpbmcsIHByb3RlaW4sIGZhdCkgJT4lIHNjYWxlCnJvdy5uYW1lcyhjbHVzdGVyX2RhdGEpIDwtIGRhdGFbLDFdCmttLnJlcyA8LSBrbWVhbnMoY2x1c3Rlcl9kYXRhLCA1LCBuc3RhcnQgPSAyNSkKZnZpel9jbHVzdGVyKGttLnJlcywgZGF0YT1jbHVzdGVyX2RhdGEsIHBhbGV0dGUgPSAiamNvIiwgZ2d0aGVtZSA9IHRoZW1lX21pbmltYWwoKSkKYGBgCgoK